package alkaid.oss.common.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * ID生成工具。
 * 
 * <p>
 * 设置环境变量：
 * <ul>
 * <li>ALKAID_WORKER_ID：必须，范围1~32</li>
 * <li>ALKAID_DATACENTER_ID：必须，范围1~32</li>
 * </ul>
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@Slf4j
public class SnowflakeUtil {
    public final static String PRO_WORKER_ID = "ALKAID_WORKER_ID";
    public final static String PRO_DATACENTER_ID = "ALKAID_DATACENTER_ID";
    public final static SnowflakeUtil INSTANCE = new SnowflakeUtil();

    private Snowflake snowflake;

    static {
        INSTANCE.initSnowflake();
    }

    private SnowflakeUtil() {
    }

    private synchronized void initSnowflake() {
        if (this.snowflake != null) {
            return;
        }

        String workerIdStr = System.getProperty(PRO_WORKER_ID);
        String datacenterIdStr = System.getProperty(PRO_DATACENTER_ID);
        if (workerIdStr == null || datacenterIdStr == null) {
            log.warn("NOTE: Set the environment variable {} and {} to initialize Snowflakeutil", PRO_WORKER_ID, PRO_DATACENTER_ID);
        }

        workerIdStr = workerIdStr == null ? "1" : workerIdStr;
        datacenterIdStr = datacenterIdStr == null ? "1" : datacenterIdStr;

        try {
            Long.valueOf(workerIdStr);
            Long.valueOf(datacenterIdStr);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(
                    "Environment variable must be number: " + PRO_WORKER_ID + ", " + PRO_DATACENTER_ID, e);
        }

        log.info("SnowflakeUtil initialized [workerId={}, datacenterId={}]", workerIdStr, datacenterIdStr);
        snowflake = IdUtil.getSnowflake(Long.valueOf(workerIdStr), Long.valueOf(datacenterIdStr));
    }

    public long nextId() {
        return snowflake.nextId();
    }

    public String nextIdStr() {
        return snowflake.nextIdStr();
    }

    public long[] nextId(final int size) {
        Assert.isTrue(size > 0, "The value must be greater than zero");

        final long[] ids = new long[size];
        for (int i = 0; i < size; i++) {
            ids[i] = snowflake.nextId();
        }
        return ids;
    }

    public String[] nextIdStr(final int size) {
        Assert.isTrue(size > 0, "The value must be greater than zero");

        final String[] ids = new String[size];
        for (int i = 0; i < size; i++) {
            ids[i] = snowflake.nextIdStr();
        }

        return ids;
    }
}
